/**
 * @file     task_audio.cpp
 * @brief   audio playing task
                support beep and wav file
                wav file format: single channel/32000/16bit PCM
 * @author    - Adela 
 *            - Robert Zhang <armner@gmail.com>
 *            - 
 *    
 *  TODO: file end with zero values
 */
#include "task_audio.h"
#include "main.h"
#include "dac_audio_driver.h"
#include "stdlib.h"
#include "string.h"
#include "ff.h"
#include "audio_file.h"
#include "wav_file.h"
#include "task_system.h"
#include "led_driver.h"
#include "FreeRTOS.h"
#include "task.h"

xQueueHandle queueAudio;

#define MAX_AUDIO_FILE  (4)

#define AUDIO_BUFFER_SIZE (1024)
/// audio_buffer for audioTask
static short audio_buffer[AUDIO_BUFFER_SIZE];
static short t_audio_data[AUDIO_BUFFER_SIZE];

#define LIMIT(x)   (x<0)?0: (x>4095)? 4095:x;
#define min(x,y)   ((x)>(y))? y:x
#define max(x,y)   ((x)>(y))? x:y

#define AUDIO_TYPE_BEEP 1
#define AUDIO_TYPE_SD_FILE 2

typedef struct t_AudioFile
{
    char fileName[64];
    FIL file;
    unsigned short type;
    unsigned short volume;
    unsigned short len;
    unsigned short current;
    unsigned short step;
    int playing;
} AudioFile;

//max 4 file supported
static AudioFile g_audio_file[MAX_AUDIO_FILE];


/**
 * @brief play a beep
 * @param freq - in Hz
 * @param ms - interval, in ms
 * @param volume - 0-4; 0 max volume, 4 min
 */
void playBeep(int freq, int ms, int volume)
{
    AudioMail audioMail;
    audioMail.prim =PRIM_AUDIO_PLAY_BEEP;
    audioMail.volume =volume;
    audioMail.data.beep.duaration =ms;
    audioMail.data.beep.freq =freq;
    xQueueSend(queueAudio, &audioMail, 10);
}

/**
 * @brief play a wav file
 * @param filename - 
 * @param volume - 0-4; 0 max volume, 4 min
 */
void playFile(char *filename, int volume)
{
    AudioMail mail;
    mail.prim =PRIM_AUDIO_PLAY_FILE;
    mail.volume =volume;
    strcpy(mail.data.name, filename);
    xQueueSend(queueAudio, &mail, 100);
}

/** @brief 
 *      Task Audio
 *       Read a queue, that have a filename to be played by audio
 *       max of 4 files to be played at the same time
 */
void taskAudio(void *pData)
{
    int t_int;
    AudioMail audioMail;

#if 1
#include "task_audio_test.h"
     xTaskCreate(taskAudioTest, (const signed char *)"taskAudioTest", TASK_AUDIO_TEST_STACK_SIZE, NULL, 2, NULL);
   
#endif

    for(t_int =0; t_int <MAX_AUDIO_FILE; t_int++)
    {
        g_audio_file[t_int].playing =0;
    }

    dac_audio_driver.open(&dac_audio_driver);
    
    while(1)
    {
        unsigned int t_audio_file;
        short *pShort;

        if(0)
        {
            char t_led;
            t_led=1;
            led_driver.write(&led_driver,&t_led, 1, 0);
        }
        
        pShort =audio_buffer;
        for( t_audio_file =0; t_audio_file<sizeof(audio_buffer)/sizeof(audio_buffer[0]); t_audio_file++)
        {
            *pShort++ =2048;
        }
        
        /// if fileLen !=0 read all files and add to the audio_buffer;
        /// else read queueAudio to check if new file available to be played
        for(t_audio_file =0; t_audio_file<MAX_AUDIO_FILE; t_audio_file++)
        {
            AudioFile &audio_file=g_audio_file[t_audio_file];

            //if(audio_file[t_int].current <audio_file[t_int].len)
            if(audio_file.playing)
            {
                int len;
                /// mix to audio_buffer[1024];
                /// if file is at end, check queueAudio for new file???
                /// may mix at next block;

                /// playing sd card file
                if(audio_file.type ==AUDIO_TYPE_SD_FILE)
                {
                    len =getWave(&audio_file.file ,t_audio_data, sizeof(t_audio_data)/sizeof(t_audio_data[0]) );
                    if(len >0)
                    {
                        int t_int;
                        for(t_int =0; t_int <len; t_int ++)
                        {
                            audio_buffer[t_int] = LIMIT(audio_buffer[t_int] + (t_audio_data[t_int]>>audio_file.volume) );
                        }

                        if(len !=sizeof(t_audio_data)/sizeof(t_audio_data[0]) )
                        {
                            audio_file.playing =0;
                            f_close(&audio_file.file);
                        }
                    }
                    else
                    {
                        audio_file.playing =0;
                        f_close(&audio_file.file);
                    }
                }

                /// playing in build file
                else if(audio_file.type == AUDIO_TYPE_BEEP)
                {
                    int t_int;
                    if(audio_file.len)
                    {
                        len =min(sizeof(audio_buffer)/sizeof(audio_buffer[0]), audio_file.len);
                        for(t_int=0; t_int<len; t_int++)
                        {
                            audio_file.current &=(SAMPLE_POINTS-1);
                            audio_buffer[t_int] = LIMIT(audio_buffer[t_int]  + (sinWave512[audio_file.current] >>audio_file.volume) );
                            audio_file.current +=audio_file.step;
                        }

                        audio_file.len -=len;
                        if(!audio_file.len)
                        {
                            audio_file.playing =0;
                        }
                    }
                    else
                    {
                        audio_file.playing =0;
                    }
#if 0
                    int t_int;
                    if(audio_file.current<audio_file.end)
                    {
                        len =min(sizeof(audio_buffer)/sizeof(audio_buffer[0]),  audio_file.end -audio_file.current);
                        for(t_int=0; t_int<len; t_int++)
                        {
                            audio_buffer[t_int] = LIMIT(audio_buffer[t_int]  + *audio_file.current );
                            audio_file.current ++;
                        }
                    }
                    else
                    {
                        audio_file.playing =0;
                    }
#endif
                }
                else
                {
                    audio_file.playing =0;
                }
            }
            else
            {
                if( xQueueReceive(queueAudio, &audioMail,0) )
                {
                    switch(audioMail.prim)
                    {
                    case PRIM_AUDIO_PLAY_FILE:
                        //if(! DISK_READY)
                        //break;

                        audioMail.data.name[19] =0;
                        strcpy(audio_file.fileName, "SOUNDS/en/");
                        strcat(audio_file.fileName, audioMail.data.name);
                        audio_file.volume =audioMail.volume<4? audioMail.volume: 4;
                        audio_file.volume +=4; ///< add more 4 bit, 16bit=>12bit
                        if(FR_OK ==  f_open(&audio_file.file, audio_file.fileName, FA_READ))
                        {
                            if( 0<checkWav(&audio_file.file) )
                            {
                                audio_file.type =AUDIO_TYPE_SD_FILE;
                                audio_file.playing =1;
                            }
                        }
                        break;

                    case PRIM_AUDIO_PLAY_BEEP:
                        audio_file.volume =audioMail.volume<4? audioMail.volume: 4;
                        audio_file.current =0;
                        audio_file.len =audioMail.data.beep.duaration*SAMPLE_RATES/1000;
                        audio_file.step = SAMPLE_POINTS +(audioMail.data.beep.freq*SAMPLE_POINTS/SAMPLE_RATES);
                        /// fixed to be a number of complete sine waves
                        audio_file.len =audio_file.len;

                        audio_file.type =AUDIO_TYPE_BEEP;
                        audio_file.playing =1;
                        break;
                    }
                }
                else
                {
#if 0
                        if(! DISK_READY)
                        break;

                        strcpy(audio_file.fileName, "SOUNDS/en/atti.wav");
                        if(FR_OK ==  f_open(&audio_file.file, audio_file.fileName, FA_READ))
                        {
                            if( 0<checkWav(&audio_file.file) )
                            {
                                audio_file.type =AUDIO_TYPE_SD_FILE;
                                audio_file.playing =1;
                            }
                        }
#endif
#if 0
/// test
                     static int t;

                     if(t++ &1)
                     {
                        audio_file.end =(short *)audioFile1;
                        audio_file.end += sizeof(audioFile1)/sizeof(audioFile1[0]);
                        audio_file.current =(short *)audioFile1;
                    }
                    else
                    {
                        audio_file.end =(short *)audioFile2;
                        audio_file.end += sizeof(audioFile2)/sizeof(audioFile2[0]);
                        audio_file.current =(short *)audioFile2;
                    }

                    t %=5;
                    audio_file.type =AUDIO_TYPE_BEEP;

                    audio_file.playing =1;
#endif
                }
            }
        }

        if(0)
        {
            char t_led;
            t_led=0;
            led_driver.write(&led_driver,&t_led, 1, 0);
        }
        dac_audio_driver.write(&dac_audio_driver, audio_buffer,sizeof(audio_buffer), 0);
    }
}

